using System;
using System.Reflection;
using UnityEngine;

namespace EntityKit.Runtime
{
    /// <summary>
    /// 普通单例基类，通过反射创建实例
    /// 支持public、private或protected无参构造函数
    /// </summary>
    /// <typeparam name="T">单例类型</typeparam>
    public class Singleton<T> : IDisposable where T : Singleton<T>
    {
        private static readonly object _lock = new object();
        private static T _instance;
        
        // 添加一个静态只读字段，用于存储类型信息，避免每次都调用typeof(T)
        private static readonly Type _type = typeof(T);

        public static T Instance
        {
            get
            {
                // 双重检查锁定模式确保线程安全
                if ((object)_instance == null)
                {
                    lock (_lock)
                    {
                        if ((object)_instance == null)
                        {
                            // 查找非公共的无参构造函数（private或protected）
                            ConstructorInfo nonPublicConstructor = _type.GetConstructor(
                                BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
                            
                            // 查找公共的无参构造函数
                            ConstructorInfo publicConstructor = _type.GetConstructor(
                                BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
                            
                            // 优先使用非公共构造函数，如果没有则使用公共构造函数
                            ConstructorInfo constructor = nonPublicConstructor ?? publicConstructor;
                            
                            if ((object)constructor == null)
                                throw new Exception(string.Format(
                                    "A parameterless constructor (public, private or protected) is missing for '{0}'.",
                                    _type.Name));

                            _instance = (T)constructor.Invoke(null);
                        }
                    }
                }

                return _instance;
            }
        }

        public void Dispose()
        {
            OnDestroy();
            _instance = null;
        }

        protected virtual void OnDestroy()
        {
        }

        /// <summary>
        /// 单例初始化回调方法
        /// 子类可以重写此方法进行初始化操作
        /// </summary>
        protected virtual void OnSingletonInit()
        {
        }

        /// <summary>
        /// 尝试获取单例实例
        /// </summary>
        /// <param name="instance">获取到的实例，如果不存在则为null</param>
        /// <returns>如果成功获取实例返回true，否则返回false</returns>
        public static bool TryGetInstance(out T instance)
        {
            instance = _instance;
            return (object)instance != null;
        }

        /// <summary>
        /// 检查单例实例是否有效
        /// </summary>
        public static bool IsInstanceValid => (object)_instance != null;

        /// <summary>
        /// 重置单例实例
        /// 主要用于测试目的
        /// </summary>
        public static void ResetInstance()
        {
            if ((object)_instance != null)
            {
                _instance.Dispose();
                _instance = null;
            }
        }
    }

    /// <summary>
    /// MonoBehaviour单例的路径属性
    /// 用于指定单例对象在层级结构中的路径
    /// </summary>
    /// <example>
    /// [MonoSingletonPath("Managers/GameManager")]
    /// public class GameManager : MonoSingleton<GameManager>
    /// {
    /// }
    /// </example>
    [AttributeUsage(AttributeTargets.Class)]
    public class MonoSingletonPath : Attribute
    {
        public MonoSingletonPath(string pathInHierarchy)
        {
            PathInHierarchy = pathInHierarchy;
        }

        public string PathInHierarchy { get; private set; }
    }

    /// <summary>
    /// MonoBehaviour单例基类
    /// 确保场景中只有一个实例存在
    /// </summary>
    /// <typeparam name="T">单例类型</typeparam>
    public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
    {
        private static T instance = null;
        private static readonly object _lock = new object();
        
        // 添加一个静态只读字段，用于存储类型信息，避免每次都调用typeof(T)
        private static readonly Type _type = typeof(T);

        public static T Instance
        {
            get
            {
                // 双重检查锁定确保线程安全
                if (instance == null)
                {
                    lock (_lock)
                    {
                        if (instance == null)
                            instance = CreateMonoSingleton();
                    }
                }
                return instance;
            }
        }

        /// <summary>
        /// 是否在场景加载时销毁单例对象
        /// 默认为false，即在场景切换时保留对象
        /// </summary>
        protected virtual bool DestroyOnLoad => false;

        protected virtual void Awake()
        {
            SetInstance(this as T);
        }

        private void SetInstance(T value)
        {
            if (instance == null)
            {
                instance = value;
                value.OnSingletonInit();
            }
            else if (instance != value)
            {
                // 如果已经存在实例且不是当前实例，则销毁当前实例
                Destroy(value.gameObject);
            }
        }

        static T CreateMonoSingleton()
        {
            if (!Application.isPlaying) 
                return null;

            var attributes = _type.GetCustomAttribute<MonoSingletonPath>(true);

            GameObject obj = null;
            if (attributes == null || string.IsNullOrEmpty(attributes.PathInHierarchy))
            {
                obj = new GameObject(_type.Name);
            }
            else
            {
                var path = attributes.PathInHierarchy;
                var subPath = path.Split('/');
                for (int i = 0; i < subPath.Length; i++)
                {
                    GameObject client = null;
                    if (obj == null)
                    {
                        client = GameObject.Find(subPath[i]);
                    }
                    else
                    {
                        var child = obj.transform.Find(subPath[i]);
                        if (child != null)
                            client = child.gameObject;
                    }

                    if (client == null)
                        client = new GameObject(subPath[i]);
                    
                    if (obj != null)
                        client.transform.SetParent(obj.transform);
                    
                    obj = client;
                }
            }

            obj.AddComponent<T>();
            if (instance.DestroyOnLoad)
            {
                if (instance.transform.parent == null)
                    DontDestroyOnLoad(instance.gameObject);
                else
                    DontDestroyOnLoad(instance.transform.root.gameObject);
            }

            return instance;
        }

        /// <summary>
        /// 单例初始化回调方法
        /// 子类可以重写此方法进行初始化操作
        /// </summary>
        protected virtual void OnSingletonInit()
        {
        }

        protected virtual void OnDestroy()
        {
            // 确保在销毁时清理静态引用
            if (instance == this)
            {
                instance = null;
            }
        }

        /// <summary>
        /// 尝试获取单例实例
        /// </summary>
        /// <param name="instance">获取到的实例，如果不存在则为null</param>
        /// <returns>如果成功获取实例返回true，否则返回false</returns>
        public static bool TryGetInstance(out T instance)
        {
            instance = MonoSingleton<T>.instance;
            return (object)instance != null;
        }

        /// <summary>
        /// 检查单例实例是否有效
        /// </summary>
        public static bool IsInstanceValid => (object)instance != null;

        /// <summary>
        /// 重置单例实例
        /// 主要用于测试目的
        /// </summary>
        public static void ResetInstance()
        {
            if ((object)instance != null)
            {
                if (Application.isPlaying)
                {
                    Destroy(instance.gameObject);
                }
                instance = null;
            }
        }
    }
}